package run.halo.app.security.filter;

import static run.halo.app.model.support.HaloConst.ADMIN_TOKEN_HEADER_NAME;
import static run.halo.app.model.support.HaloConst.ADMIN_TOKEN_QUERY_NAME;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import run.halo.app.cache.AbstractStringCacheStore;
import run.halo.app.config.properties.HaloProperties;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.model.entity.User;
import run.halo.app.security.authentication.Authentication;
import run.halo.app.security.authentication.AuthenticationImpl;
import run.halo.app.security.context.SecurityContextHolder;
import run.halo.app.security.context.SecurityContextImpl;
import run.halo.app.security.handler.DefaultAuthenticationFailureHandler;
import run.halo.app.security.service.OneTimeTokenService;
import run.halo.app.security.support.UserDetail;
import run.halo.app.service.OptionService;
import run.halo.app.service.UserService;

/**
 * 后台用户鉴权，非管理员只能发文章
 */
@Slf4j
@Component
@Order(2)
public class BackgroundUserFilter extends AbstractAuthenticationFilter{
    private final HaloProperties haloProperties;



    public BackgroundUserFilter(AbstractStringCacheStore cacheStore,
        UserService userService,
        HaloProperties haloProperties,
        OptionService optionService,
        OneTimeTokenService oneTimeTokenService,
        ObjectMapper objectMapper) {
        super(haloProperties, optionService, cacheStore, oneTimeTokenService);
        this.haloProperties = haloProperties;

        addUrlPatterns("/api/admin/**");

        addExcludeUrlPatterns(
            "/api/admin/login",
            "/api/admin/refresh/*",
            "/api/admin/installations",
            "/api/admin/migrations/halo",
            "/api/admin/is_installed",
            "/api/admin/password/code",
            "/api/admin/password/reset",
            "/api/admin/login/precheck",
            "/api/admin/themes/activation/template/custom/post",
            "/api/admin/themes/activation",
            "/api/admin/logout",
            "/api/admin/tags",
            "/api/admin/tags/**",
            "/api/admin/posts",
            "/api/admin/posts/**",
            "/api/admin/sheets/**",
            "/api/admin/journals/**",
            "/api/admin/logs/**",
            "/api/admin/categories/**",
            "/api/admin/categories",
            "/api/admin/users/**",
            "/api/admin/statistics/user",
            "/api/admin/statistics",
            "/api/admin/backups/markdown/import"
        );


        // set failure handler
        DefaultAuthenticationFailureHandler failureHandler =
            new DefaultAuthenticationFailureHandler();
        failureHandler.setProductionEnv(haloProperties.getMode().isProductionEnv());
        failureHandler.setObjectMapper(objectMapper);
        setFailureHandler(failureHandler);
    }
    @Override
    protected String getTokenFromRequest(HttpServletRequest request) {

        return getTokenFromRequest(request, ADMIN_TOKEN_QUERY_NAME, ADMIN_TOKEN_HEADER_NAME);
    }

    @Override
    protected void doAuthenticate(HttpServletRequest request, HttpServletResponse response,
        FilterChain filterChain) throws ServletException, IOException {
         if (!haloProperties.isAuthEnabled()) {

            // Do filter
            filterChain.doFilter(request, response);
            return;
        }

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetail userDetail = authentication.getDetail();
        User user = userDetail.getUser();
        //  1代表管理员 ，非1是非管理员
        if(user.getUserRole() != 1){
            throw new ForbiddenException("无权限");
        }

        // Set security
        SecurityContextHolder
            .setContext(new SecurityContextImpl(new AuthenticationImpl(userDetail)));

        // Do filter
        filterChain.doFilter(request, response);
    }
}
